home *** CD-ROM | disk | FTP | other *** search
/ Complete Internet Archive / Complete Internet Archive.iso / Page Counters / Page Counters.txt < prev    next >
Text File  |  1997-01-26  |  21KB  |  813 lines

  1.  
  2.  
  3. #! /usr/bin/perl
  4.  
  5. # cgi-bin access counter program
  6. # Version 4.0.5
  7. #
  8. # Copyright (C) 1995 George Burgyan
  9. #
  10. # This program is free software; you can redistribute it and/or modify
  11. # it under the terms of the GNU General Public License as published by
  12. # the Free Software Foundation; either version 2 of the License, or (at
  13. # your option) any later version.
  14. # This program is distributed in the hope that it will be useful, but
  15. # WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. # General Public License for more details.
  18. #
  19. # A full copy of the GNU General Public License can be retrieved from
  20. # http://www.webtools.org/counter/copying.html
  21. #
  22. # gburgyan@webtools.org
  23. #
  24. # George Burgyan
  25. # 1380 Dill Road
  26. # South Euclid, OH 44121
  27. #
  28. # For more information look at http://www.webtools.org/counter/
  29.  
  30. ########################################################################
  31. #
  32. #   CHANGE THESE TO SUIT YOUR SITE
  33. #
  34.  
  35. # The default language option (english, french, swedish)
  36. $default_lang = "english";
  37.  
  38. # The name of the file to use.  You should probably give this an absolute path
  39. $FileName = "access_count";
  40.  
  41. # Replace with a list of regular expression IP addresses that we
  42. # are supposed to ignore.  If you don't know what this means, just use
  43. # "\." instead of periods.  Comment out entirely to ignore nothing.
  44.  
  45. #@IgnoreIP = ("199\.18\.203\..*",
  46. #          "199\.18\.159\.1",
  47. #          );
  48.  
  49. # Aliases: Set this up so that diffent pages will all yield the same
  50. # count.  For instance, if you have a link like "index.html -> home.html"
  51. # set it up like ("/index.html", "/home.html").  Make sure you give a full
  52. # path to it. This will treat "/index.html" as if it were "/home.html".
  53.  
  54. %Aliases = ("/fakename.html", "/realname.html",
  55.             "/index.html", "/home.html",
  56.         );
  57.  
  58.  
  59. # AUTOMATICALLY SET BY INSTALL!!   Modify only if necessary!!!
  60. #
  61. # BaseName: set to whatever you have counter installed as.  This is
  62. # used to derive the arguments.  No not touch the next comment.
  63.  
  64. ### AUTOMAGIC ###
  65. $BaseName = "counter";
  66.  
  67. # counter  or  counterbanner  or  counterfiglet
  68. #
  69. # Outputs the number of times a specific page has been accessed.
  70. # The output depends on which page 'called' it, and what the program
  71. # is named:
  72. #
  73. # The counter can "take arguments" via its name.  That is, if you tack
  74. # -arg to the end of the program name, -arg is taken to be an argument.
  75. # For example, if you call the counter 'counter-ord', '-ord' is considered
  76. # an argument, and an ordinal count (1st, 2nd, 3rd, ...) will be printed
  77. # instead of (1, 2, 3, ...).  Note that counterord does the same thing as
  78. # counter-ord for backward compatibility.
  79. #
  80. # Currently recognized arguments:
  81. #
  82. #  -f=font    sets "font" to be the font for figlet
  83. #  -lang=lang   sets the language used to ordinalize to "lang"
  84. #  -nc        no count; don't to write the incremented count back to the file
  85. #  -nl        no link; don't automatically generate a link
  86. #  -nd          no display; don't display anything, just count
  87. #  -ord        make an ordinal count instead of regular
  88. #  -doc=document override the DOCUMENT_URI environment variable
  89. #
  90. # Example:  counterfiglet-ord-f=bigfont-nc
  91. #
  92. # This will cause the counter to call figlet as the output routine, printing
  93. # in a big font an ordinal count, without updating the access count file.
  94. # Note that the order of arguments is irrelevant so long as you spell the
  95. # file name correctly.  It is generally assumed that the ability to take
  96. # different arguments/use different output routines is done with symlinks:
  97. # i.e. ln -s counter counterfiglet-ord-f=bigfont-nc
  98. #
  99. # More complete documentation can be found at
  100. # http://www.webtools.org/counter/
  101. #
  102. ########################################################################
  103. #
  104. # Thing that shouldn't really need changing, but are configurable anyway.
  105. #
  106.  
  107. # Maximum number of times to try to lock the file.
  108. # Each try is .1 second.  Try for 1 second.
  109. $MaxTries = 10;
  110.  
  111. # Set this to point to something, or comment it out, and it
  112. # won't be a link at all.
  113. $Link = "http://www.webtools.org/counter/";
  114.  
  115. # Whether or not to use locking.  If perl complains that flock is not
  116. # defined, change this to 0.  Not *really* necessary because we check
  117. # to make sure it works properly.
  118. $UseLocking = 1;
  119.  
  120. # What version of the counter file format are we using?
  121. $FileVersion = "02.000";
  122.  
  123. # Common names of the counter to install...
  124. @CommonExtensions = ("-ord",      # Ordinam
  125.              "figlet",      # Figlet'ed
  126.              "figlet-ord",# Ordinal figlet
  127.              "banner",    # Bannered
  128.              "banner-ord",# Ordinal banner
  129.              );
  130. #
  131. #########################################################################
  132. #
  133. # Misc documents to refer people to in case of errors.
  134. #
  135. $CreateFile = "<a href=\"http://www.webtools.org/counter/faq.html#create\">[Error Creating Counter File -- Click for more info]</a>";
  136. $AccessRights = "<a href=\"http://www.webtools.org/counter/faq.html#rights\">[Error Opening Counter File -- Click for more info]</a>";
  137. $TimeoutLock = "[Timeout locking counter file]";
  138. $BadVersion = "<a href=\"http://www.webtools.org/counter/\">[Version access_count newer than this program.  Please upgrade.]</a>";
  139.  
  140. #########################################################################
  141. #
  142. # The actual program!
  143.  
  144. ### Stage 1
  145. ###
  146. ### Parse the arguments...  (just ignore this part)
  147.  
  148. # Get arguments from program name.  Argh...what a horrible way to do it!
  149. $prog = $0;
  150. $prog =~ s/(\.cgi|\.pl)//;      #strip .cgi|.pl name extension
  151. $prog =~ s!^(.*/)!!;        # separate program name
  152. $prog =~ s/\\(.)/sprintf("%%%02x", ord($1))/ge;    # quote \c to %xx
  153.  
  154. ($printer, @args) = split(/-/, $prog);    # args are separated by dashes
  155. $printer =~ s/%(..)/pack("c", hex($1))/ge; # unquote printer function name
  156. $printer =~ s/$BaseName/counter/; # Make it cannonical.
  157.  
  158. # This gets path info, which is only applicable if you are using our
  159. # ssis script (see above).  This makes counter/ord the same as counter-ord
  160. push(@args, split("/", $ENV{"PATH_INFO"})) if $ENV{"PATH_INFO"};
  161.  
  162. # put them in assoc array %arg
  163. foreach (@args)    # means do this for each element in the array
  164. {
  165.     s/%(..)/pack("c", hex($1))/ge;    # unquote %xx
  166.     /^([^=]*)=?(.*)$/;            # extract "=" part, if any
  167.     $arg{$1} = $2 ? $2 : 1;
  168. }
  169.  
  170. if ($ARGV[0] eq '-install') {
  171.     &CheckPerl;
  172.     &SetBaseName;
  173.     &MakeCommon(0);
  174.     exit(0);
  175. }
  176.  
  177. if ($ARGV[0] eq '-installforce') {
  178.     &CheckPerl;
  179.     &SetBaseName;
  180.     &MakeCommon(1);
  181.     exit(0);
  182. }
  183.  
  184. if ($ARGV[0] eq '-unlock') {
  185.     open(FILE,"$FileName");
  186.     &UnlockFile(FILE);
  187.     exit(0);
  188. }
  189.  
  190. undef $Link if $arg{'nl'};    # make link?
  191.  
  192. ### Stage 2
  193. ###
  194. ### Print out the header
  195.  
  196. # Print out the header
  197. print "Content-type: text/html\n\n";
  198.  
  199.  
  200.  
  201. ### Stage 3
  202. ###
  203. ### Open the access_count file for read-write taking all the precautions
  204.  
  205. # Make sure the file exists:
  206. if (!(-f $FileName)) {
  207.     if (!open (COUNT,">$FileName")) {
  208.     # Can't create the file
  209.     print $CreateFile;
  210.     exit 1;
  211.     } else {
  212.     # We got the file, print out the version number
  213.     print COUNT "$FileVersion\n";
  214.     $version = 2;
  215.     }
  216. } else {
  217.     if (!((-r $FileName) && (-w $FileName))) {
  218.     # Make sure that we can in fact read and write to the file in
  219.     # question.  If not, direct them to the FAQ.
  220.     print $AccessRights;
  221.     exit 1;
  222.     }
  223.  
  224.     if (!open (COUNT,"+<$FileName")) {    # Now make sure it *really* opens
  225.     print $AccessRights;            # ...just in case...
  226.     exit 1;
  227.     }
  228.  
  229.     # Try to read in a version number
  230.     $version = <COUNT>;
  231.     if (!($version =~ /^\d+.\d+$/)) {
  232.     # No version number, assume version 1 and reset the file.
  233.     $version = 1;
  234.     seek(COUNT,0,0);
  235.     }
  236. }
  237.  
  238. # This is for the future: the access_count file will have a version number.
  239. if ($version > 2) {
  240.     print $BadVersion;
  241.     exit 1;
  242. }
  243.  
  244. ### Stage 4
  245. ###
  246. ### Attempt to lock the file
  247.  
  248.  
  249. $lockerror = &LockFile(COUNT);
  250.  
  251. # You would figure that $MaxTries would equal 0 if it didn't work.  The
  252. # post-decrement takes it to -1 when the loop finally exits.
  253. if ($lockerror) {
  254.     print $TimeoutLock;
  255.     exit(0);
  256. }
  257.  
  258.  
  259. ### Stage 5
  260. ###
  261. ### Check if we need to update the file to a newer version
  262.  
  263. if ($version < 2) {
  264.     &UpdateVersion1;
  265. }
  266.  
  267.  
  268. ### Stage 6
  269. ###
  270. ### Convert the information the server gave us into the document
  271. ### identifier.
  272.  
  273. # Make sure perl doesn't spit out warnings...
  274. if (defined $ENV{'DOCUMENT_URI'}) {
  275.     $doc_uri = $ENV{'DOCUMENT_URI'};
  276. } else {
  277.     $doc_uri = "";
  278. }
  279.  
  280. # Campatibility: Version 2 files have the server name in front if and
  281. # only if it doesn't have a "~" in it.
  282.  
  283. $old_uri = $doc_uri;
  284.  
  285. # Add the server name in front to support multi-homed hosts if and only if
  286. # it doesn't have a "~" in it.  (usernames are global in most multi-homed
  287. # settings
  288. if (defined $ENV{'SERVER_NAME'} && !($doc_uri =~ /~/)) {
  289.     $doc_uri = $ENV{'SERVER_NAME'} . "/" . $doc_uri;
  290. }
  291.  
  292. if (defined $arg{'doc'}) {
  293.     $doc_uri = $arg{'doc'};
  294. }
  295.  
  296. $doc_uri = $Aliases{$doc_uri} if defined $Aliases{$doc_uri};
  297.  
  298.  
  299. ### Stage 7
  300. ###
  301. ### Find the relevant place in the file
  302.  
  303. $location = tell COUNT;
  304. while ($line = <COUNT>) {
  305.     # Read the file line-by-line.
  306.     if (($uri,$accesses) = ($line =~ /^'(\S*)' (\d\d\d\d\d\d\d\d\d\d)$/)) {
  307.     # An old line
  308.     if ($uri eq $old_uri) {
  309.         &ConvertDocV1($doc_uri,$old_uri,$accesses,$location);
  310.         last;
  311.     }
  312.     } elsif (($uri,$accesses,$flags) = ($line =~ /^'(\S*)' (\d\d\d\d\d\d\d\d\d\d) (\w\w\w\w)$/)) {
  313.     # A new line
  314.     if ($uri eq $doc_uri) {
  315.         $flags = hex($flags);
  316.         last;
  317.     }
  318.     }
  319.  
  320.     last if ($uri eq $doc_uri);
  321.     $location = tell COUNT;
  322.     
  323.     #reset the fields
  324.     $accesses = 0;
  325.     $flags = 0;
  326. }
  327.  
  328.  
  329. ### Stage 8
  330. ###
  331. ### Update the access count of the file
  332.  
  333. $accesses += 1;    # *NOT* '++' because we don't want '++'s magic
  334.  
  335.  
  336. ### Stage 9
  337. ###
  338. ### Figure out what to print out
  339.  
  340. # If we have to ordinalize, do it now.
  341. if (defined $arg{'ord'}) {
  342.     if (defined $arg{'lang'}) {
  343.     $ord = eval("&ordinalize_$arg{lang}($accesses)");
  344.     } else {
  345.     $ord = &ordinalize($accesses);
  346.     }
  347. } else {
  348.     $ord = "";
  349. }
  350. $to_print = $accesses . $ord;
  351.  
  352. # Give it to the printer function to actually produce the output from the
  353. # ascii text that we have (to_print)
  354. ($count, $nLink) = eval("&output_$printer('$to_print')");
  355.  
  356. # If the above line gave us an error, default to just the text.
  357. if ($@) {
  358.     ($count, $nLink) = &output_counter($to_print);
  359. }
  360.  
  361. ### Stage 10
  362. ###
  363. ### Now we actually tell the browser what the count is.
  364.  
  365. if (! $arg{"nd"} ) {        # If we print anything
  366.     # Print out a link to something informative (if we were requested to)
  367.     print "<a href=\"$nLink\">" if $nLink;
  368.     print $count;
  369.     print "</a>" if $nLink;
  370. }
  371.  
  372.  
  373. ### Stage 11
  374. ###
  375. ### Check if we are supposed to update the count in the file.  (ie. we're
  376. ### not ignoring the host that just accessed us)
  377.  
  378. # Make sure we are not ignoring the host:
  379.  
  380. $ignore = 0;
  381. $ignore = grep($ENV{"REMOTE_ADDR"} =~ /$_/, @IgnoreIP) if defined ($ENV{"REMOTE_ADDR"});
  382. $ignore = $ignore || $arg{"nc"};
  383.  
  384. ### Stage 12
  385. ###
  386. ### Actually write the updated information back to the file
  387.  
  388. if (!$ignore)            # If we aren't ignoring this access
  389. {
  390.     # Now update the counter file
  391.     seek(COUNT, $location, 0);
  392.     $longaccesses = sprintf("%010.10d", $accesses);
  393.     $hexflags = sprintf("%04.4x", $flags);
  394.     print COUNT "'$doc_uri' $longaccesses $hexflags\n";
  395. }
  396.  
  397. &UnlockFile(COUNT);
  398.  
  399. close COUNT;
  400.  
  401. #######################################################################
  402. #
  403. # Support functions
  404. #
  405.  
  406. # translate_output
  407. #
  408. # Quote any special characters with HTML quoting.
  409.  
  410. sub translate_output {
  411.     local($string) = @_;
  412.  
  413.     $_ = $string;
  414.   
  415.     s/Φ/è/g;
  416.  
  417.     return $_;
  418. }
  419.  
  420. sub LockFile {
  421.     local(*FILE) = @_;
  422.     local($TrysLeft) = $MaxTries;
  423.  
  424.     if ($UseLocking) {
  425.     # Try to get a lock on the file
  426.     while ($TrysLeft--) {
  427.         
  428.         # Try to use locking, if it doesn't use locking, the eval would
  429.         # die.  Catch that, and don't use locking.
  430.  
  431.         # Try to grab the lock with a non-blocking (4) exclusive (2) lock.
  432.         # (4 | 2 = 6)
  433.         $lockresult = eval("flock(COUNT,6)");
  434.  
  435.         if ($@) {
  436.         $UseLocking = 0;
  437.         last;
  438.         }
  439.  
  440.         if (!$lockresult) {
  441.         select(undef,undef,undef,0.1); # Wait for 1/10 sec.
  442.         } else {
  443.         last;        # We have gotten the lock.
  444.         }
  445.     }
  446.     }
  447.  
  448.     if ($TrysLeft >= 0) {
  449.     # Success!
  450.     return 0;
  451.     } else {
  452.     return -1;
  453.     }
  454. }
  455.  
  456. sub UnlockFile {
  457.     local(*FILE) = @_;
  458.  
  459.     if ($UseLocking) {
  460.     flock(FILE,8);            # Unlock the file.
  461.     }
  462. }
  463.  
  464.  
  465. ####################################################################
  466. #
  467. # Installation helpers
  468. #
  469.  
  470.  
  471. # SetBaseName
  472. #
  473. # Change the counter program itself to set the basename
  474.  
  475. sub SetBaseName {
  476.     local($name) = $0;
  477.  
  478.     $name =~ s/^.*\/([^\/]+)$/$1/; # Strip off any of the path
  479.     
  480.     if ($name eq $BaseName) {    # The way we're set up now!!!
  481.     return;            # Don't need to change a thing.
  482.     }
  483.     
  484.     if (!open(COUNTERFILE, "+<$0")) {
  485.     print "Can't modify program.  Set \$BaseName manually.\n";
  486.     return;
  487.     }
  488.  
  489.     print "Configuring \$BaseName variable...\n";
  490.  
  491.     local($oldsep) = $/;
  492.     undef($/);
  493.  
  494.     local($program) = <COUNTERFILE>;
  495.     
  496.     # The next line does all the magic.
  497.     $program =~ s/\#\#\# AUTOMAGIC \#\#\#\n\$BaseName = \"[^\"]+\";\n/\#\#\# AUTOMAGIC \#\#\#\n\$BaseName = \"$name\";\n/;
  498.  
  499.     seek(COUNTERFILE,0,0) || return;
  500.     truncate(COUNTERFILE,0);
  501.     print COUNTERFILE $program;
  502.     close COUNTERFILE;
  503. }
  504.     
  505. # CheckPerl
  506. #
  507. # Make sure that the "#! /[path]/perl" points to something real...
  508.  
  509. sub CheckPerl {
  510.     if (!open(COUNTERFILE, "<$0")) {
  511.     print "Can't check to make sure Perl is in the right place.\n";
  512.     return;
  513.     }
  514.     print "Checking to make sure Perl is found properly...\n";
  515.  
  516.     $firstline = <COUNTERFILE>;
  517.     ($command) = ($firstline =~ /^\#! *([^\s]+) *$/);
  518.     close(COUNTERFILE);
  519.  
  520.     if (! -x $command) {
  521.     print "The location of Perl is misconfigured.  Please edit the\n";
  522.     print "first line of this program to point to the locally installed\n";
  523.     print "copy of perl.\n\n";
  524.     print "Currently, it is configured to be \"$command\", however,\n";
  525.     print "that file either does not exist or is not a program.\n\n";
  526.     print "Some common locations for Perl are:\n";
  527.     print "  /usr/bin/perl\n";
  528.     print "  /usr/local/bin/perl\n";
  529.     print "  /opt/gnu/bin/perl\n\n";
  530.         exit;
  531.     }
  532. }
  533.  
  534. # MakeCommon
  535. #
  536. # Make some common links to the counter
  537.  
  538. sub MakeCommon {
  539.     local($force) = @_;
  540.     local($ext);
  541.  
  542.     print "Installing the counter...\n";
  543.     print "   ...making counter executable\n";
  544.     chmod(0755,$0);
  545.  
  546.     local($path, $name, $cgi);
  547.     $name = $0;
  548.     if ($name =~ /^(.*\/)([^\/]+)$/) {
  549.     $path = $1; $name = $2;
  550.     }
  551.     if ($name =~ /^(.*)(\.cgi)$/) {
  552.     $name = $1, $cgi = $2;
  553.     }
  554.  
  555.     foreach $ext (@CommonExtensions) {
  556.     print  "   ...making link from $path$name$cgi to $path$name$ext$cgi\n";
  557.     if (!&MakeLink("$path$name$cgi","$path$name$ext$cgi",$force)) {
  558.         # An error occured while making the link.  :-(
  559.  
  560.         print "     *** An error occured while making the link.\n";
  561.     }
  562.     }
  563.     if ($symlink_exists == 0 && $link_exists == 0) {
  564.     print "* NOTE *  Your system does not support symbolic or hard links,\n";
  565.         print "          copies made instead.  If you modify the counter, you must\n";
  566.     print "          run counter -install again to recopy it to the other files.\n";
  567.     }
  568.  
  569.     print "...done!\n";
  570. }
  571.  
  572. # MakeLink
  573. #
  574. # Actually create the link.
  575.  
  576. sub MakeLink {
  577.     local($oldname,$newname,$force) = @_;
  578.  
  579.     # Check to see if we can make symbolic links instead of hard links
  580.     if (!defined $symlink_exists) {
  581.     $symlink_exists = (eval 'symlink("","");', $@ eq '');
  582.     }
  583.  
  584.     # Check to see if we can make a link if we can't make a symlink
  585.     if (!symlink_exists) {
  586.     $link_exists = (eval 'link("","");', $2 eq '');
  587.     }
  588.  
  589.     if ($force) {
  590.     # Check to see if the file exists
  591.     if (-e $newname) {
  592.         if (!unlink ($newname)) {
  593.         return 0;
  594.         }
  595.     }
  596.     }
  597.  
  598.     if ($symlink_exists) {
  599.     return symlink($oldname, $newname);
  600.     } elsif ($link_exists) {
  601.     return link($oldname, $newname);
  602.     } else {
  603.     # Copy it the old-fashioned way...  *sigh*
  604.     open(OLDFILE, $oldname) || die "Can't open $oldname for copy";
  605.     open(NEWFILE, ">$newname") || die "Can't open $newname for write";
  606.     while(<OLDFILE>) {
  607.         print NEWFILE $_;
  608.     }
  609.     close(NEWFILE);
  610.     close(OLDFILE);
  611.     }
  612. }
  613.  
  614. ####################################################################
  615. #
  616. # Ordinalizing functions
  617. #
  618.  
  619. # ordinalize
  620. #
  621. # Call the appropriate ordinalize function for the default language
  622.  
  623. sub ordinalize
  624. {
  625.     local($count) = @_;
  626.  
  627.     if (defined $arg{'lang'}) {
  628.     return eval("&ordinalize_$arg{lang}($count)");
  629.     } else {
  630.     return eval("&ordinalize_$default_lang($count)");
  631.     }
  632. }
  633.  
  634.  
  635. # ordinalize_english
  636. #
  637. # Figure out what suffix (st, nd, rd, th) a number would have in ordinal
  638. # form and return that extension.
  639.  
  640. sub ordinalize_english {
  641.     local($count) = @_;
  642.     local($last, $last2);
  643.  
  644.     $last2 = $count % 100;
  645.     $last = $count % 10;
  646.  
  647.     if ($last2 < 10 || $last2 > 13) {
  648.     return "st" if $last == 1;
  649.     return "nd" if $last == 2;
  650.     return "rd" if $last == 3;
  651.     }
  652.  
  653.     return "th";        # Catch "eleventh, twelveth, thirteenth" etc.
  654. }
  655.  
  656. # ordinalize_french
  657. #
  658. # Trivial...  Return the extension for french.  The only exception is 1.
  659. # Thank you Chris Polewczuk <chris@hexonx.com>
  660.  
  661. sub ordinalize_french {
  662.     local ($count) = @_;
  663.  
  664.     if ($count == 1) {
  665.     return "'iΦre";
  666.     } else {
  667.     return "iΦme";
  668.     }
  669. }
  670.  
  671. # ordinalize_swedish
  672. #
  673. # A function to ordinalize in Swedish.  Thanks go to Johan Linde
  674. # <jl@theophys.kth.se> for the code!
  675.  
  676. sub ordinalize_swedish {
  677.     local($count) = @_;
  678.     local($last, $last2);
  679.  
  680.     $last2 = $count % 100;
  681.     $last = $count % 10;
  682.  
  683.     if ($last2 < 10 || $last2 > 12) {
  684.         return ":a" if ($last == 1 || $last == 2);
  685.     }
  686.  
  687.     return ":e";
  688. }
  689.  
  690.  
  691. ########################################################################
  692. #
  693. # Output functions
  694. #
  695. # The following are the routines that actually convert the number
  696. # of accesses into something that we print out.
  697. #
  698. # The name of each function is "output_" followed by the program's name.
  699. # For instance, is the program is called "counter" then "output_counter"
  700. # will be called; a program called "counterbanner" will call
  701. # "output_counterbanner" to get the output.
  702. #
  703. # If the function is not defined, then "output_counter" will be called.
  704. #
  705.  
  706. # output_counter
  707. #
  708. # The simplest function: just returns the number of accesses and the link.
  709.  
  710. sub output_counter {
  711.     local($count) = @_;
  712.  
  713.     return &translate_output($count), $Link; # we return the count and the link
  714. }
  715.  
  716.  
  717. # output_counterord
  718. #
  719. # Return the number of accesses as an ordinal number.  (ie. 1st, 2nd, 3rd, 4th)
  720.  
  721. sub output_counterord {
  722.     local($count) = @_;
  723.  
  724.     return &translate_output($count . &ordinalize($count)), $Link;
  725. }
  726.  
  727.  
  728. # output_counterbanner
  729. #
  730. # A somewhat silly one that uses the "banner" command to print out the
  731. # count.  :)  You might need to change the path to make it work.
  732.  
  733. sub output_counterbanner {
  734.     local($count) = @_;
  735.     
  736.     $banner = `banner $count`;
  737.  
  738.     return "<pre>$banner</pre>"; # return no link here (it would be annoying)
  739. }
  740.  
  741.  
  742. # output_counterfiglet
  743. #
  744. # An even sillier one than counterbanner.  :)
  745.  
  746. sub output_counterfiglet {
  747.     local($count) = @_;
  748.  
  749.     $fig = "echo $count | /usr/games/figlet";    # setup command line
  750.     $fig .= " -f $arg{'f'}" if $arg{"f"};    # use a different font?
  751.     $fig = `$fig`;
  752.     $fig =~ s!&!&!;
  753.     $fig =~ s!<!<!;
  754.     return "<br><pre>" . $fig . "</pre>";    # note no link here, either
  755. }
  756.  
  757.  
  758.  
  759. #########################################################################
  760. #
  761. # Conversion functions
  762. #
  763.  
  764. # UpdateVersion
  765. #
  766. # Convert a version 1file into a version 2 file.
  767.  
  768. sub UpdateVersion1 {
  769.     local ($contents,$dummy);
  770.     local ($oldsep) = $/;
  771.  
  772.     $/ = "";
  773.     seek(COUNT,0,0);        # Go to the beginning of the file
  774.     $contents = <COUNT>;
  775.     seek(COUNT,0,0);
  776.     print COUNT "$FileVersion\n";
  777.     print COUNT $contents;
  778.     seek(COUNT,0,0);
  779.     $/ = $oldsep;
  780.     $dummy = <COUNT>;        # Skip the new line
  781. }
  782.  
  783.  
  784. # ConvertDocV1
  785. #
  786. # Convert the a version 1 line into a version 2 line
  787.  
  788. sub ConvertDocV1 {
  789.     local ($doc_uri,$old_uri,$accesses,$location) = @_;
  790.     local ($contents,$dummy,$oldsep);
  791.  
  792.     $oldsep = $/;
  793.  
  794.     seek (COUNT,$location,0);    # Skip the line in question
  795.     $dummy = <COUNT>;
  796.     
  797.     $/ = "";            # Read in the whole file
  798.     $contents = <COUNT>;
  799.  
  800.     seek (COUNT,$location,0);
  801.     
  802.     local ($longaccesses,$hexflags);
  803.     $longaccesses = sprintf("%010.10d", $accesses);
  804.     $hexflags = sprintf("%04.4x", $flags);
  805.  
  806.     # Print out the new stuff
  807.     print COUNT "'$doc_uri' $longaccesses $hexflags\n";
  808.     print COUNT $contents;
  809.  
  810.     $/ = $oldsep;
  811. }
  812.